import 'dart:io';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:file_picker/file_picker.dart';
import 'package:http/http.dart' as http;
import 'package:path/path.dart' as path;
import 'package:archive/archive.dart';
import 'package:path_provider/path_provider.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '文件夹压缩上传',
      theme: ThemeData(primarySwatch: Colors.blue, useMaterial3: true),
      home: const FolderUploadScreen(),
    );
  }
}

class FolderUploadScreen extends StatefulWidget {
  const FolderUploadScreen({super.key});

  @override
  State<FolderUploadScreen> createState() => _FolderUploadScreenState();
}

class _FolderUploadScreenState extends State<FolderUploadScreen> {
  List<File> _selectedFiles = [];
  bool _isUploading = false;
  bool _isCompressing = false;
  double _uploadProgress = 0.0;
  String _uploadStatus = '准备上传';
  String? _selectedFolderPath;
  int _totalFiles = 0;
  int _compressedFiles = 0;

  Future<void> _pickFolder() async {
    try {
      String? selectedDirectory = await FilePicker.platform.getDirectoryPath();

      if (selectedDirectory != null) {
        final dir = Directory(selectedDirectory);
        List<File> files = [];

        // 递归获取文件夹中的所有文件
        await _getFilesFromDirectory(dir, files);

        setState(() {
          _selectedFiles = files;
          _selectedFolderPath = selectedDirectory;
          _uploadProgress = 0.0;
          _uploadStatus = '已选择 ${files.length} 个文件';
          _totalFiles = files.length;
        });
      }
    } catch (e) {
      ScaffoldMessenger.of(
        context,
      ).showSnackBar(SnackBar(content: Text('选择文件夹时出错: $e')));
    }
  }

  Future<void> _getFilesFromDirectory(Directory dir, List<File> files) async {
    await for (var entity in dir.list(recursive: true)) {
      if (entity is File) {
        files.add(entity);
      }
    }
  }

  Future<File> _compressFolder(String folderPath, List<File> files) async {
    setState(() {
      _isCompressing = true;
      _compressedFiles = 0;
      _uploadStatus = '正在压缩文件夹...';
    });

    final archive = Archive();

    for (var file in files) {
      // 计算相对路径
      String relativePath = path.relative(file.path, from: folderPath);

      // 读取文件内容
      List<int> bytes = await file.readAsBytes();

      // 添加到压缩包
      archive.addFile(ArchiveFile(relativePath, bytes.length, bytes));

      setState(() {
        _compressedFiles++;
        _uploadStatus = '压缩中: $_compressedFiles/$_totalFiles';
      });
    }

    // 编码为ZIP格式
    List<int>? zipData = ZipEncoder().encode(archive);

    if (zipData == null) {
      throw Exception('压缩失败');
    }

    // 保存到临时文件
    final tempDir = await getTemporaryDirectory();
    final zipFile = File(
      '${tempDir.path}/upload_${DateTime.now().millisecondsSinceEpoch}.zip',
    );
    await zipFile.writeAsBytes(zipData);

    setState(() {
      _isCompressing = false;
      _uploadStatus = '压缩完成，准备上传';
    });

    return zipFile;
  }

  Future<void> _uploadCompressedFile() async {
    if (_selectedFiles.isEmpty || _selectedFolderPath == null) return;

    setState(() {
      _isUploading = true;
      _uploadProgress = 0.0;
      _uploadStatus = '开始压缩...';
    });

    try {
      // 先压缩文件夹
      File zipFile = await _compressFolder(
        _selectedFolderPath!,
        _selectedFiles,
      );

      setState(() {
        _uploadStatus = '开始上传压缩文件...';
      });

      // 创建上传请求
      var request = http.MultipartRequest('POST', Uri.parse('你的上传URL'));

      // 添加压缩文件
      var stream = http.ByteStream(zipFile.openRead());
      var length = await zipFile.length();

      var multipartFile = http.MultipartFile(
        'zipfile', // 根据你的后端API调整字段名
        stream,
        length,
        filename: path.basename(zipFile.path),
      );

      // 添加原始文件夹名称，供服务器解压时使用
      request.fields['folder_name'] = path.basename(_selectedFolderPath!);

      request.files.add(multipartFile);

      // 发送请求并监听进度
      var response = await http.Response.fromStream(await request.send());

      if (response.statusCode == 200) {
        setState(() {
          _uploadStatus = '上传成功! 服务器正在解压...';
          _uploadProgress = 1.0;
        });

        // 等待服务器解压完成（可选）
        // 这里可以添加一个轮询机制来检查服务器解压状态
        await _checkServerExtractionStatus();
      } else {
        setState(() {
          _uploadStatus = '上传失败: ${response.statusCode}';
        });
      }

      // 删除临时压缩文件
      await zipFile.delete();
    } catch (e) {
      setState(() {
        _uploadStatus = '上传出错: $e';
      });
    } finally {
      setState(() {
        _isUploading = false;
      });
    }
  }

  Future<void> _checkServerExtractionStatus() async {
    // 这里可以实现与服务器的状态检查
    // 例如，定期请求服务器获取解压状态
    // 这是一个可选功能，取决于你的服务器API

    // 模拟等待
    await Future.delayed(const Duration(seconds: 2));

    setState(() {
      _uploadStatus = '所有文件上传并解压完成!';
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('文件夹压缩上传'),
        backgroundColor: Colors.blue[700],
        foregroundColor: Colors.white,
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            // 选择文件夹按钮
            ElevatedButton(
              onPressed: _isUploading ? null : _pickFolder,
              style: ElevatedButton.styleFrom(
                backgroundColor: Colors.blue[600],
                foregroundColor: Colors.white,
                padding: const EdgeInsets.symmetric(vertical: 16),
              ),
              child: const Text('选择文件夹', style: TextStyle(fontSize: 16)),
            ),

            const SizedBox(height: 20),

            // 文件信息展示
            Card(
              elevation: 3,
              child: Padding(
                padding: const EdgeInsets.all(16.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      '文件信息',
                      style: TextStyle(
                        fontSize: 18,
                        fontWeight: FontWeight.bold,
                        color: Colors.grey[800],
                      ),
                    ),
                    const SizedBox(height: 10),
                    Text(
                      _selectedFiles.isEmpty
                          ? '未选择任何文件夹'
                          : '已选择 ${_selectedFiles.length} 个文件',
                      style: TextStyle(fontSize: 16, color: Colors.grey[700]),
                    ),
                    if (_selectedFolderPath != null) ...[
                      const SizedBox(height: 10),
                      Text(
                        '文件夹: ${path.basename(_selectedFolderPath!)}',
                        style: TextStyle(fontSize: 14, color: Colors.grey[600]),
                      ),
                    ],
                    if (_selectedFiles.isNotEmpty) ...[
                      const SizedBox(height: 10),
                      SizedBox(
                        height: 150,
                        child: ListView.builder(
                          itemCount: _selectedFiles.length,
                          itemBuilder: (context, index) {
                            return ListTile(
                              leading: const Icon(
                                Icons.insert_drive_file,
                                size: 20,
                              ),
                              title: Text(
                                path.basename(_selectedFiles[index].path),
                                overflow: TextOverflow.ellipsis,
                                style: const TextStyle(fontSize: 14),
                              ),
                            );
                          },
                        ),
                      ),
                    ],
                  ],
                ),
              ),
            ),

            const SizedBox(height: 20),

            // 进度条
            if (_isCompressing) ...[
              LinearProgressIndicator(
                value: _totalFiles > 0 ? _compressedFiles / _totalFiles : 0,
                backgroundColor: Colors.grey[300],
                valueColor: AlwaysStoppedAnimation<Color>(Colors.orange[700]!),
                minHeight: 10,
                borderRadius: BorderRadius.circular(5),
              ),
              const SizedBox(height: 10),
            ] else if (_isUploading) ...[
              LinearProgressIndicator(
                value: _uploadProgress,
                backgroundColor: Colors.grey[300],
                valueColor: AlwaysStoppedAnimation<Color>(Colors.blue[700]!),
                minHeight: 10,
                borderRadius: BorderRadius.circular(5),
              ),
              const SizedBox(height: 10),
            ],

            // 上传状态文本
            Text(
              _uploadStatus,
              textAlign: TextAlign.center,
              style: TextStyle(
                fontSize: 16,
                color:
                    _uploadStatus.contains('成功') || _uploadStatus.contains('完成')
                    ? Colors.green
                    : _uploadStatus.contains('失败') ||
                          _uploadStatus.contains('出错')
                    ? Colors.red
                    : Colors.grey[700],
              ),
            ),

            const SizedBox(height: 20),

            // 上传按钮
            ElevatedButton(
              onPressed: _isUploading || _selectedFiles.isEmpty
                  ? null
                  : _uploadCompressedFile,
              style: ElevatedButton.styleFrom(
                backgroundColor: Colors.green[600],
                foregroundColor: Colors.white,
                padding: const EdgeInsets.symmetric(vertical: 16),
              ),
              child: _isUploading || _isCompressing
                  ? const Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        SizedBox(
                          width: 20,
                          height: 20,
                          child: CircularProgressIndicator(
                            strokeWidth: 2,
                            valueColor: AlwaysStoppedAnimation<Color>(
                              Colors.white,
                            ),
                          ),
                        ),
                        SizedBox(width: 10),
                        Text('处理中...', style: TextStyle(fontSize: 16)),
                      ],
                    )
                  : const Text('压缩并上传', style: TextStyle(fontSize: 16)),
            ),
          ],
        ),
      ),
    );
  }
}
